(function(){
  /**
   * @returns {TokenConfigInfo}
   */
  function getTokenConfigInfo() {
    var eContext = $.ecity.top;
    if (
      !eContext.g_ctx ||
      typeof eContext.g_ctx.getToken !== 'function' ||
      typeof eContext.g_ctx.getCfgByKey !== 'function'
    ) {
      return null;
    }
    var g_ctx = eContext.g_ctx;
    var initCfg = g_ctx.getCfgByKey('init');
    var defaultTokenType = 'url';
    var defaultTokenKey = 'access_token';
    if (initCfg.default.tokenBearer) {
      if (initCfg.default.tokenBearer.type) {
        defaultTokenType = initCfg.default.tokenBearer.type;
      }
      if (initCfg.default.tokenBearer.key) {
        defaultTokenKey = initCfg.default.tokenBearer.key;
      }
    }
    return {
      tokenType: defaultTokenType,
      tokenKey: defaultTokenKey,
      token: g_ctx.getToken(),
    };
  }
  function getNextUrlWithToken(url) {
    var tokenConfigInfo = getTokenConfigInfo();
    if (tokenConfigInfo === null) {
      return url;
    }
    if (tokenConfigInfo.tokenType !== 'url') {
      return url;
    }
    if (url.indexOf(tokenConfigInfo.tokenKey) > -1) {
      return url;
    }
    var preUrl = '';
    var newUrl = url;
    // 针对 proxy.jsp 做特殊处理
    var proxyIndex = newUrl.indexOf('proxy.jsp');
    if (proxyIndex > -1) {
      preUrl = newUrl.substring(0, proxyIndex + 10);
      newUrl = newUrl.substring(proxyIndex + 10);
    }
    if (newUrl.indexOf('?') === -1) {
      newUrl += '?';
    } else {
      if (newUrl.indexOf('?') !== newUrl.length - 1) {
        newUrl += '&';
      }
    }
    newUrl += tokenConfigInfo.tokenKey + '=' + tokenConfigInfo.token;
    return preUrl + newUrl;
  }
  /**
   * 验证是否在 g_ctx 存在指定的属性值
   * @param {string} propName - 属性名称
   */
  function hasGlobalContextProperty(propName) {
    var eContext = $.ecity.top;
    return eContext && eContext.g_ctx && eContext.g_ctx[propName];
  }
  /**
   * 基于 ck 的额外参数传递
   * @param {string} url - 一个必有参数的 url 地址
   * @returns {string}
   */
  function getNextUrlWithExtra(url) {
    // get server log id
    var params = parseQueryString(url);
    if ('ck' in params) {
      var k = params.ck;
      if (hasGlobalContextProperty('cacheHelper')) {
        var v = $.ecity.top.g_ctx.cacheHelper.get('systemLog').get(k);
        // 2020-08-14 存在为空的场景，from 王冠华
        if (v) {
          var nextExtraParams = {};
          Object.keys(v).forEach(function (key) {
            if (!params.hasOwnProperty(key)) {
              nextExtraParams[key] = v[key];
            }
          });

          var extraUrl = Object.keys(nextExtraParams)
            .map(function (k) {
              return k + '=' + nextExtraParams[k];
            })
            .join('&');
          if (extraUrl.length > 0) {
            url += '&' + extraUrl;
          }
        }
      }
    }
    return url;
  }

  function parseQueryString(url) {
    var arr;
    var res = {};
    url = url.split('#')[0];
    arr = url.split('?');
    arr.shift();
    var queryStr = arr.join('?');
    if (queryStr.trim().length == 0) {
      return res;
    }
    arr = queryStr.split('&');
    for (var i = 0; i < arr.length; i++) {
      var itemArr = arr[i].split('=');
      var name = itemArr.shift();
      var value = itemArr.join('=');
      res[name] = value;
    }
    return res;
  }
// 覆写 XMLHttpRequest，已实现 token 自动传递 by caizhongjie 2019/12/05
  var origOpen = XMLHttpRequest.prototype.open;
  var origSend = XMLHttpRequest.prototype.send;
  var origSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
  XMLHttpRequest.prototype.open = function (method, url, async, username, password) {
    var nextUrl = url;
    // STD
    this.__signInjector = new SignInjector();
    if (!/^(blob|data):/.test(url)) {
      var nextUrl = getNextUrlWithToken(url);
      nextUrl = getNextUrlWithExtra(nextUrl);
      nextUrl = this.__signInjector.open(this, nextUrl, method);
      // END
    }
    return origOpen.call(this, method, nextUrl, async, username, password);
  };

  XMLHttpRequest.prototype.send = function (body) {
    handleHeaderToken(this);
    handleHeaderLanguage(this);
    body = this.__signInjector.send(body);
    return origSend.call(this, body);
  };

  XMLHttpRequest.prototype.setRequestHeader = function (name, value) {
    this.__hack = this.__hack || {};
    if (this.__hack[name]) {
      return;
    } else {
      // 针对 www 重新设置请求头，增加 charset=UTF-8 by caizhongjie 2021/07/08
      if (value === 'application/x-www-form-urlencoded') {
        value = 'application/x-www-form-urlencoded; charset=UTF-8';
      }
      this.__hack[name] = value;
      this.__signInjector.setRequestHeader(name, value);
      origSetRequestHeader.call(this, name, value);
    }
  };

  var SignInjector = function () {
    this.data = { shouldSign: false, signed: false, headers: {}, method: null, params: {} };
    this.xhr = null;
  };
  SignInjector.prototype.open = function (xhr, nextUrl, method) {
    if (/^(blob|data):/.test(nextUrl)) {
      return nextUrl;
    }
    this.xhr = xhr;
    var holder = this.data;
    var ctx = $.ecity.top.g_ctx;
    if (ctx && ctx.signHelper) {
      var signHelper = ctx.signHelper;
      var url = signHelper.parseUrl(nextUrl);
      var flag = signHelper.shouldMountSign(url.pathname);
      var queryString = url.query.slice(1);
      var params = signHelper.parseQuery(queryString);
      if (!params.sys) {
        params.sys =
          ctx.configHelper && typeof ctx.configHelper.getInit === 'function' && (ctx.configHelper.getInit() || {}).sys;
      } else {
        // console.warn('XSR:sys exists');
      }
      holder.shouldSign = flag;
      holder.method = method;
      if (flag) {
        var signed = method.toLowerCase() === 'get';
        holder.signed = signed;
        holder.params = params;
        if (signed) {
          var signParams = signHelper.sign(params);
          console.log('签名数据 REQ:', signParams);
          nextUrl = nextUrl.replace(/\?.+/, '?' + signParams.toString());
        }
      }
    }
    return nextUrl;
  };
  SignInjector.prototype.send = function (body) {
    var holder = this.data;
    var ctx = $.ecity.top.g_ctx;
    if (ctx && ctx.signHelper) {
      var signHelper = ctx.signHelper;
      if (holder.shouldSign && !holder.signed) {
        console.log('未签名：', holder.headers);
        var contentType = holder.headers['content-type'];
        if (contentType) {
          var ct = contentType.toLowerCase();
          if (ct.indexOf('application/x-www-form-urlencoded') > -1) {
            var p = holder.params;
            var pp = signHelper.parseQuery(body || '');
            var params = Object.assign({}, pp, p);
            var signParams = signHelper.sign(params);
            console.log('签名数据 REQ:', signParams);
            body = signParams.toString();
          }
        }
      }
    }
    return body;
  };
  SignInjector.prototype.setRequestHeader = function (name, value) {
    this.data.headers[name.toLowerCase()] = value;
  };
})()
